#ifndef CPUFALLOC_H
#define CPUFALLOC_H
#define FALLOC_H

/*
 *	This is the header file supporting cpuFalloc.c and defining both the host and device-side interfaces. See that file for some more
 *	explanation and sample use code. See also below for details of the host-side interfaces.
 *
 *  Quick sample code:
 *
	#include "cpuFalloc.c"

	int main()
	{
		cpuFallocHost heap = cpuFallocInit();
		fallocInit(heap.heap);

		// create/free heap
		void* obj = fallocGetChunk(heap.heap);
		fallocFreeChunk(heap.heap, obj);

		// create/free alloc
		fallocContext* ctx = fallocCreateCtx(heap.heap);
		char* testString = (char*)falloc(ctx, 10);
		int* testInteger = falloc<int>(ctx);
		fallocDisposeCtx(ctx);

		// free and exit
		cpuFallocEnd(heap);
        return 0;
	}
 */


///////////////////////////////////////////////////////////////////////////////
// DEVICE SIDE
// External function definitions for device-side code

typedef struct _cpuFallocHeap fallocHeap;
void fallocInit(fallocHeap* heap);
void* fallocGetChunk(fallocHeap* heap);
void* fallocGetChunks(fallocHeap* heap, size_t length, size_t* allocLength = nullptr);
void fallocFreeChunk(fallocHeap* heap, void* obj);
void fallocFreeChunks(fallocHeap* heap, void* obj);
// ALLOC
typedef struct _cpuFallocContext fallocContext;
fallocContext* fallocCreateCtx(fallocHeap* heap);
void fallocDisposeCtx(fallocContext* ctx);
void* falloc(fallocContext* ctx, unsigned short bytes, bool alloc = true);
void* fallocRetract(fallocContext* ctx, unsigned short bytes);
void fallocMark(fallocContext* ctx, void* &mark, unsigned short &mark2);
bool fallocAtMark(fallocContext* ctx, void* mark, unsigned short mark2);
//
template <typename T> T* falloc(fallocContext* ctx) { return (T*)falloc(ctx, sizeof(T), true); }
template <typename T> void fallocPush(fallocContext* ctx, T t) { *((T*)falloc(ctx, sizeof(T), false)) = t; }
template <typename T> T fallocPop(fallocContext* ctx) { return *((T*)fallocRetract(ctx, sizeof(T))); }

//#if 1==1
// ATOMIC
//typedef struct _cpuFallocAutomic fallocAutomic;
//fallocAutomic* fallocCreateAtom(fallocHeap* heap, unsigned short pitch, size_t length);
//void fallocDisposeAtom(fallocAutomic* atom);
//void* fallocAtomNext(fallocAutomic* atom, unsigned short bytes);
//#endif

///////////////////////////////////////////////////////////////////////////////
// HOST SIDE
// External function definitions for host-side code

typedef struct {
	fallocHeap* heap;
	int length;
	void* reserved;
} cpuFallocHost;

//
//	cpuFallocInit
//
//	Call this to initialise a falloc heap. If the buffer size needs to be changed, call cudaFallocEnd()
//	before re-calling cudaFallocInit().
//
//	The default size for the buffer is 1 megabyte. For CUDA
//	architecture 1.1 and above, the buffer is filled linearly and
//	is completely used.
//
//	Arguments:
//		length - Length, in bytes, of total space to reserve (in device global memory) for output.
//
//	Returns:
//		cudaSuccess if all is well.
//
extern "C" cpuFallocHost cpuFallocInit(size_t length=1048576, void* reserved=nullptr);   // 1-meg

//
//	cpuFallocEnd
//
//	Cleans up all memories allocated by cudaFallocInit() for a heap.
//	Call this at exit, or before calling cudaFallocInit() again.
//
extern "C" void cpuFallocEnd(cpuFallocHost &heap);


#ifdef TRACE
///////////////////////////////////////////////////////////////////////////////
// TRACE: HOST SIDE

typedef struct _cpuFallocTrace cpuFallocTrace;

//
//	cpuFallocWTraceInit
//
//	Call this to initialise a falloc heap. If the buffer size needs to be changed, call cudaFallocEnd()
//	before re-calling cudaFallocInit().
//
//	The default size for the buffer is 1 megabyte. For CUDA
//	architecture 1.1 and above, the buffer is filled linearly and
//	is completely used.
//
//	Arguments:
//		length - Length, in bytes, of total space to reserve (in device global memory) for output.
//
//	Returns:
//		cudaSuccess if all is well.
//
extern "C" cpuFallocHost cpuFallocWTraceInit(size_t length=1048576);   // 1-meg

//
//	cpuFallocWTraceEnd
//
//	Cleans up all memories allocated by cudaFallocInit() for a heap.
//	Call this at exit, or before calling cudaFallocInit() again.
//
extern "C" void cpuFallocWTraceEnd(cpuFallocHost &host);

//
//  cpuFallocSetTraceInfo
//
//	Sets a trace Info.
//
extern "C" void cpuFallocSetTraceInfo(size_t id, bool showDetail);

//
//  cpuFallocTraceInit
//
//	Creates a trace Stream.
//
extern "C" cpuFallocTrace* cpuFallocTraceInit();

//
//	cpuFallocTrace
//
//	Streams till empty.
//
extern "C" void* cpuFallocTraceStream(cpuFallocHost &host, cpuFallocTrace* trace, size_t &length);

//
//  cpuFallocTraceEnd
//
//	Frees a trace Stream.
//
extern "C" void cpuFallocTraceEnd(cpuFallocTrace* trace);

#endif

#endif // CPUFALLOC_H
